package com.miplus.ccrm.core.service.action;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.yulichang.base.MPJBaseServiceImpl;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.miplus.ccrm.common.*;
import com.miplus.ccrm.core.controller.vo.action.*;
import com.miplus.ccrm.core.controller.vo.conf.WfNextStepVo;
import com.miplus.ccrm.core.controller.vo.credit.CrdCaseResVo;
import com.miplus.ccrm.core.pojo.ConCustomer;
import com.miplus.ccrm.core.pojo.CreditAccount;
import com.miplus.ccrm.core.pojo.FiAmort;
import com.miplus.ccrm.core.mapper.FiAmortMapper;
import com.miplus.ccrm.core.pojo.FiCreditcases;
import com.miplus.ccrm.core.service.ExportService;
import com.miplus.ccrm.core.service.FiWorkFlowCase;
import com.miplus.ccrm.core.service.conf.MsgAlertsService;
import com.miplus.ccrm.core.service.crd.FiImportHistService;
import com.miplus.ccrm.core.service.crd.FiTaskService;
import com.miplus.ccrm.core.service.file.FiApplyAttService;
import com.miplus.ccrm.core.service.strategy.CpCalllistService;
import com.miplus.ccrm.core.utils.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
* @author pc
* @description 针对表【fi_amort(协商分期表)】的数据库操作Service实现
* @createDate 2024-04-12 21:15:04
*/
@Slf4j
@Service
public class FiAmortServiceImpl extends MPJBaseServiceImpl<FiAmortMapper, FiAmort>
    implements FiAmortService{
    @Resource
    private FiTaskService fiTaskService;
    @Resource
    private CpCalllistService cpCalllistService;
    @Resource
    private FiWorkFlowCase fiWorkFlowCase;
    @Resource
    private FiAmortDetailService fiAmortDetailService;
    @Resource
    private FiApplyAttService fiApplyAttService;
    @Resource
    private MsgAlertsService msgAlertsService;
    @Resource
    private ExportService exportService;
    @Resource
    private FiImportHistService fiImportHistService;

    @Override
    public IPage<FiAmortResVo> fiAmortList(JSysUser user, FiApplyReqVo paras)
    {
        String $usrid=user.getUsrid();
        String idstar= JUsrPerm.getPermission(user,JUsrPerm.DISSTAR_IDNO);
        String cardstar= JUsrPerm.getPermission(user,JUsrPerm.DISSTAR_CARD);
        //2024-09-03.apply(JPubUtils.IsEmpty(paras.getFicaseid()) 如果通过案件ID打开（就是案件详情进入的，这种情况不需要控制fc_hasApplyView）
        return selectJoinListPage(new Page<>(paras.getPageNum(), paras.getPageSize()),
                FiAmortResVo.class,
                new MPJLambdaWrapper<FiAmort>()
                        .selectAs("DATE_FORMAT(t.confirmdt,'%Y-%m-%d %H:%i:%s')",FiAmortResVo::getConfirmdt)
                        .selectAs("DATE_FORMAT(t.canceldt,'%Y-%m-%d %H:%i:%s')",FiAmortResVo::getCanceldt)
                        .selectAs("DATE_FORMAT(t.firstpaydate,'%Y-%m-%d %H:%i:%s')",FiAmortResVo::getFirstpaydate)
                        .selectAs("DATE_FORMAT(t.applydt,'%Y-%m-%d %H:%i:%s')",FiAmortResVo::getApplydt)
                        .selectAs("fun_getnames('BUSINESS.TYPE',fi.prodtype)", FiAmortResVo::getProdtype)
                        .selectAs("fun_getnames('FI.AMORT.STATUS',t.status)", FiAmortResVo::getStatusdsc)
                        .selectAs("fun_getnames('FI.AMORT.REASON',t.applyreason)", FiAmortResVo::getApplyreason)
                        .selectAs("(select cl.wfid from cp_calllist cl where cl.clid=t.clid)", FiAmortResVo::getWfid)
                        .selectAs("(select g.GRPNAME from sys_user u join sys_grp g on u.GROUPS=g.GRPID where u.USRID=t.applyusr)",FiAmortResVo::getApplygrp)
                        .selectAs("(select count(1)+1 from fi_amort_detail d where d.amortid=t.applynumber and d.paydate<now())",FiAmortResVo::getCurrnumber)
                        .selectAs("(select count(1) from fi_amort_detail d where d.amortid=t.applynumber and d.status in(0,2,3))",FiAmortResVo::getBabcount)
                        .selectAs(ConCustomer::getCustname,FiAmortResVo::getCustname)
                        .selectAs(String.format("fi_starSecu('%s','%s',cu.openacctcertno,'%s')", $usrid, JUsrPerm.DISSTAR_IDNO, idstar), FiAmortResVo::getIdnumber)
                        .selectAs(String.format("fi_starSecu('%s','%s',cda.crdt_card_repe_no,'%s')", $usrid, JUsrPerm.DISSTAR_CARD, cardstar), FiAmortResVo::getCardno)
                        .selectAs("(select sum(case when am.amount is null then 0.0 else am.amount end) from fi_amort_detail am where am.amortid=t.applynumber)",FiAmortResVo::getResumamount)
                        .selectAs("(select sum(case when am.repayment is null then 0.0 else am.repayment end) from fi_amort_detail am where am.amortid=t.applynumber)",FiAmortResVo::getRepayment)
                        .selectAs("(t.amount-(select sum(case when am.repayment is null then 0.0 else am.repayment end) from fi_amort_detail am where am.amortid=t.applynumber))",FiAmortResVo::getRemainpay)
                        .leftJoin(FiCreditcases.class,"fi",FiCreditcases::getCreditcaseid,FiAmort::getFicaseid)
                        .leftJoin(ConCustomer.class,"cu",ConCustomer::getCustomernumber,FiCreditcases::getCustomernumber)
                        .leftJoin(CreditAccount.class,"cda",CreditAccount::getAcct,FiCreditcases::getCreditAcct)
                        .selectAll(FiAmort.class)
                        .select(CreditAccount::getAcct)
                        .apply(JPubUtils.IsEmpty(paras.getFicaseid()),"fc_hasApplyView(t.applynumber,'SYS_AMORT',t.applyusr,{0},t.status,t.confirmusr)>0",$usrid)
                        .apply(JPubUtils.IsNotEmpty(paras.getApplygrp()),"fc_hasUsrInGroup(t.applyusr,{0})>0",paras.getApplygrp())
                        .eq(JPubUtils.IsNotEmpty(paras.getFicaseid()),FiAmort::getFicaseid,paras.getFicaseid())
                        .eq(JPubUtils.IsNotEmpty(paras.getStatus()), FiAmort::getStatus,paras.getStatus())
                        .eq(JPubUtils.IsNotEmpty(paras.getApplyusr()),FiAmort::getApplyusr,paras.getApplyusr())
                        .between(JPubUtils.IsNotEmpty(paras.getStartdt()),FiAmort::getApplydt,JPubUtils.StringToDate(paras.getStartdt()),JPubUtils.StringToDate(paras.getEnddt()))
                        .in(JPubUtils.IsNotEmpty(paras.getAcctlist()),CreditAccount::getAcct,paras.getAcctlist())
                        .in(JPubUtils.IsNotEmpty(paras.getStatuslist()),FiAmort::getStatus,paras.getStatuslist())
                        .orderByDesc(FiAmort::getApplydt)
        );
    }

    @Override
    @Transactional
    public CmdResVo fiAmortAdd(JSysUser user, FiAmortAddVo paras)
    {
        String $usrid=user.getUsrid();
        //1=待审核
        FiAmort fiAmort=selectJoinOne(FiAmort.class,
                new MPJLambdaWrapper<FiAmort>()
                        .eq(FiAmort::getFicaseid,paras.getFicaseid())
                        .in(FiAmort::getStatus,
                                EnumConfirmStatus.Pending.value,
                                EnumConfirmStatus.Pass.value,
                                EnumConfirmStatus.Process.value)
        );
        //相同的案件正在审核中
        if(fiAmort!=null){
            if(fiAmort.getStatus()==EnumConfirmStatus.Pending.value) {
                throw new ServiceException(EnumRCode.DataPending.value, EnumRCode.DataPending.name);
            }
            else if(fiAmort.getStatus()==EnumConfirmStatus.Pass.value||
                    fiAmort.getStatus()==EnumConfirmStatus.Process.value){
                throw new ServiceException(EnumRCode.NoFinish.value, EnumRCode.NoFinish.name);
            }
        }
        String clid=paras.getClid();
        if(JPubUtils.IsEmpty(clid)){
            clid="SYS_AMORT"; //此任务是系统配置任务，不能delete
        }

        //2024-07-08
        String prem=JUsrPerm.getPermission(user,"WF.AMORT.CONFIRM2");
        log.info("fiAmortAdd.ficase={},has={}",paras.getFicaseid(),prem);

        Integer wfid=0;
        if(JPubUtils.IsEmpty(prem)) {//需要工作流，否则跳过工作流,2024-07-08
            wfid=cpCalllistService.getCalllistWfID(clid);
        }

        int tasknumber=fiTaskService.addTask($usrid,clid,paras.getFicaseid(), EnumFiChannel.Amort.value);

        int ret=0;
        log.info("applyAdd:clid={},ficase={},tasknumber={},wfid={}",clid,paras.getFicaseid(),tasknumber,wfid);

        FiAmort fi = new FiAmort();
        BeanUtils.copyProperties(paras,fi);
        fi.setClid(clid);
        fi.setTasknumber(tasknumber);
        fi.setApplydt(new Date());
        fi.setApplyusr($usrid);
        if(JPubUtils.IsEmpty(prem)) {
            fi.setStatus(EnumConfirmStatus.New.value); //新建
        }
        else{
            fi.setStatus(EnumConfirmStatus.Pass.value); //通过
            fi.setConfirmdt(new Date());
            fi.setConfirmusr($usrid);
            fi.setConfirmdsc("自动审批通过");

            fiTaskService.updateStatus(tasknumber, $usrid, "P");
        }
        ret=baseMapper.insert(fi);

        int applynumber=fi.getApplynumber();

        //添加协商分期明细
        fiAmortDetailService.doAdd(applynumber,paras);

        fiApplyAttService.AddApplyFile(applynumber,EnumFiChannel.Amort.toString().toLowerCase(),paras.getUploadList());

        if(wfid>0){
            String status=fiWorkFlowCase.doCreate($usrid,wfid,applynumber,tasknumber);
            fi = new FiAmort();
            fi.setApplynumber(applynumber);
            fi.setStatus(Integer.parseInt(status)); //处理中
            baseMapper.updateById(fi);
        }

        return new CmdResVo(ret,Integer.toString(applynumber));
    }

    @Override
    public CmdResVo fiAmortCancel(String $usrid, FiApplyCancelVo paras)
    {
        FiAmort fi=baseMapper.selectById(paras.getApplynumber());
        if(JPubUtils.IsNotEmpty(fi.getTasknumber())){
            fiTaskService.updateStatus(fi.getTasknumber(),$usrid,"X");
        }
        else{
            log.warn("applyCancel:getTasknumber.isnull");
        }
        Integer wfid=cpCalllistService.getCalllistWfID(fi.getClid());
        fiWorkFlowCase.doCancel($usrid,wfid,fi.getApplynumber());

        fi = new FiAmort();
        fi.setApplynumber(paras.getApplynumber());
        fi.setStatus(EnumConfirmStatus.Cancel.value); //终止
        fi.setCancelusr($usrid);
        fi.setCanceldt(new Date());
        int ret=baseMapper.updateById(fi);

        //取消明细
        fiAmortDetailService.doCannel(paras.getApplynumber());

        return new CmdResVo(ret,fi.getApplynumber().toString());
    }

    @Override
    public CmdResVo fiAmortConfirm(String $usrid, FiApplyConfirmVo paras)
    {
        boolean confirmend=true;
        String okstatus=paras.getActionid().toString();

        FiAmort fiAmort=baseMapper.selectById(paras.getApplynumber());

        if(JPubUtils.IsNotEmpty(paras.getCaseactid())){
            //需要走工作流
            WfNextStepVo wfNextStepVo=fiWorkFlowCase.doExec($usrid,paras.getCaseactid(),
                    paras.getActionid(),paras.getWfcaseid(),paras.getConfirmdsc()
            );
            okstatus=wfNextStepVo.getStatus();

            //可能有多级审核,3=审核全部完成
            if(!JPubUtils.IsEqual(wfNextStepVo.getType(), EnumWorkFlowStep.End.value)) {
                confirmend=false;
            }

            if(JPubUtils.IsEqual(okstatus, EnumConfirmStatus.NoPass.value)){
                //审核不通过，把明细状态取消，2024-06-05
                fiAmortDetailService.doCannel(paras.getApplynumber());
            }
        }
        else{
            Integer wfid=cpCalllistService.getCalllistWfID(fiAmort.getClid());
            if(wfid==null||wfid==0){//不使用工作流,这种情况下okstatus就是字典ID，直接写审核结果
                log.info("fiAmortConfirm.nouse workflow：okstatus={}",okstatus);
            }
            else{//可能配置错误或网络引起的，2024-08-29
                log.warn("fiAmortConfirm.nofind wf caseactid.");
                throw new ServiceException(EnumRCode.WfDataErr.value, EnumRCode.WfDataErr.name);
            }
        }

        //单纯就是审批流程，结果后续操作就在这里写，如果有后续反馈的，在result里面写，比如外访
        if(JPubUtils.IsNotEmpty(fiAmort.getTasknumber())&&confirmend) {
            fiTaskService.updateStatus(
                    fiAmort.getTasknumber(),
                    $usrid,
                    fiWorkFlowCase.getPassStatus(okstatus)
            );
            msgAlertsService.msgAlertAdd(EnumFiChannel.Amort,
                    fiAmort.getApplyusr(),
                    $usrid,EnumUtil.ConfirmStatusName(okstatus)
            );
        }

        FiAmort fi = new FiAmort();
        fi.setApplynumber(paras.getApplynumber());
        fi.setStatus(Integer.parseInt(okstatus));
        fi.setConfirmusr($usrid);
        fi.setConfirmdt(new Date());
        fi.setConfirmdsc(paras.getConfirmdsc());
        int ret=baseMapper.updateById(fi);

        return new CmdResVo(ret,paras.getApplynumber().toString());
    }

    @Override
    public List<FiAmortDetailVo> fiAmortPre(FiAmortAddVo paras)
    {
        List<FiAmortDetailVo> fiAmortDetailVoList = new LinkedList<>();
        try {
            FiAmortDetailVo fiAmortDetail = new FiAmortDetailVo();
            fiAmortDetail.setStatus(EnumFiAmortDStatus.WaitPay.value);
            fiAmortDetail.setStatusdsc(EnumFiAmortDStatus.WaitPay.name);
            fiAmortDetail.setPernumber(1);
            fiAmortDetail.setPaydate(paras.getFirstpaydate());
            fiAmortDetail.setAmount(paras.getFirstamount());
            fiAmortDetail.setAmountsum(paras.getFirstamount());
            //fiAmortDetail.setPrin(paras.getFirstprin());
            //fiAmortDetail.setInterest(paras.getFirstinterest());
            //fiAmortDetail.setExpense(paras.getExpense());

            double reamount=paras.getAmount().doubleValue()-paras.getFirstamount().doubleValue();
            fiAmortDetail.setReamount(BigDecimal.valueOf(reamount));

            fiAmortDetailVoList.add(fiAmortDetail);

            SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(paras.getFirstpaydate());
            String dtimeval = formatter.format(calendar.getTime());
            dtimeval = dtimeval.substring(0, 7) + "-01";
            Date dtime = formatter.parse(dtimeval);

            int num=paras.getPernumber()-1;
            double amount=reamount/num;
            double amountsum=paras.getFirstamount().doubleValue();
            DecimalFormat decimalFormat=new DecimalFormat(".00");
            //double prin=(paras.getPrin().doubleValue()-paras.getFirstprin().doubleValue())/num;
            //double interest=(paras.getInterest().doubleValue()-paras.getFirstinterest().doubleValue())/num;
            //double expense=(paras.getExpense().doubleValue()-paras.getFirstexpense().doubleValue())/num;

            for (int i = 2; i <= paras.getPernumber(); i++) {
                fiAmortDetail = new FiAmortDetailVo();
                fiAmortDetail.setStatus(EnumFiAmortDStatus.WaitPay.value);
                fiAmortDetail.setStatusdsc(EnumFiAmortDStatus.WaitPay.name);
                fiAmortDetail.setPernumber(i);
                Date dt=JPubUtils.addMonths(dtime,i-1);
                dt=JPubUtils.addDays(dt,paras.getEverypayday()-1);
                fiAmortDetail.setPaydate(dt);
                fiAmortDetail.setAmount(new BigDecimal(decimalFormat.format(amount)));
                //fiAmortDetail.setPrin(BigDecimal.valueOf(prin));
                //fiAmortDetail.setInterest(BigDecimal.valueOf(interest));
                ///fiAmortDetail.setExpense(BigDecimal.valueOf(expense));
                reamount-=amount;
                fiAmortDetail.setReamount(new BigDecimal(decimalFormat.format(reamount)));

                amountsum+=amount;
                fiAmortDetail.setAmountsum(new BigDecimal(decimalFormat.format(amountsum)));

                fiAmortDetailVoList.add(fiAmortDetail);
            }
        }
        catch (Exception e){
            throw new ServiceException(EnumRCode.DateFormat.value, EnumRCode.DateFormat.name);
        }

        return fiAmortDetailVoList;
    }

    @Override
    public CmdResVo fiAmortStop(String $usrid, FiApplyCancelVo paras)
    {//分期终止
        FiAmort fi = new FiAmort();
        fi.setApplynumber(paras.getApplynumber());
        fi.setStatus(EnumConfirmStatus.Stop.value); //终止
        fi.setCancelusr($usrid);
        fi.setCanceldt(new Date());
        int ret=baseMapper.updateById(fi);

        //终止明细
        fiAmortDetailService.doCannel(paras.getApplynumber());

        return new CmdResVo(ret,fi.getApplynumber().toString());
    }

    @Override
    public CmdResVo expAmort(JSysUser user, FiApplyReqVo paras, HttpServletResponse response)
    {
        String $usrid=user.getUsrid();

        IPage<FiAmortResVo> pages=fiAmortList(user, paras);
        ArrayList arr=new ArrayList();

        String exptempid=JPubUtils.getExpTempID(paras.getExpfilename(),"协商分期列表");
        String filename=JPubUtils.getExpFileName(
                paras.getExpfilename(),exptempid
        );
        pages.convert(u->{
            HashMap map=JPubUtils.toExportMap(u);
            if(map!=null) arr.add(map);
            return u;
        });
        CmdResVo resVo=exportService.ToExcel(
                response,
                arr,
                paras.getExpidlist(),
                paras.getExpnamelist(),
                filename,
                $usrid
        );

        int okcount=resVo.getCount();
        if(okcount>0){
            fiImportHistService.AddExportHist(
                    resVo.getKeyId(),
                    $usrid,
                    exptempid,
                    filename,
                    okcount
            );
        }

        return resVo;
    }
}




